home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows 95 / Programming Windows 95.iso / code / CHAP17 / SHOWPOP1.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-01  |  12.1 KB  |  361 lines

  1. /*-----------------------------------------
  2.    SHOWPOP1.C -- DDE Client using DDEPOP1
  3.                  (c) Charles Petzold, 1996
  4.   -----------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include <dde.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "showpop.h"
  11.  
  12. #define WM_USER_INITIATE (WM_USER + 1)
  13. #define DDE_TIMEOUT      3000
  14.  
  15. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
  16.  
  17. char szAppName[] = "ShowPop1" ;
  18.  
  19. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  20.                     PSTR szCmdLine, int iCmdShow)
  21.      {
  22.      HWND       hwnd ;
  23.      MSG        msg ;
  24.      WNDCLASSEX wndclass ;
  25.  
  26.      wndclass.cbSize        = sizeof (wndclass) ;
  27.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  28.      wndclass.lpfnWndProc   = WndProc ;
  29.      wndclass.cbClsExtra    = 0 ;
  30.      wndclass.cbWndExtra    = 0 ;
  31.      wndclass.hInstance     = hInstance ;
  32.      wndclass.hIcon         = LoadIcon (hInstance, szAppName) ;
  33.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  34.      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  35.      wndclass.lpszMenuName  = NULL ;
  36.      wndclass.lpszClassName = szAppName ;
  37.      wndclass.hIconSm       = LoadIcon (hInstance, szAppName) ;
  38.  
  39.      RegisterClassEx (&wndclass) ;
  40.  
  41.      hwnd = CreateWindow (szAppName, "DDE Client - US Population",
  42.                           WS_OVERLAPPEDWINDOW,
  43.                           CW_USEDEFAULT, CW_USEDEFAULT,
  44.                           CW_USEDEFAULT, CW_USEDEFAULT,
  45.                           NULL, NULL, hInstance, NULL) ;
  46.  
  47.      ShowWindow (hwnd, iCmdShow) ;
  48.      UpdateWindow (hwnd) ;
  49.  
  50.      SendMessage (hwnd, WM_USER_INITIATE, 0, 0L) ;
  51.  
  52.      while (GetMessage (&msg, NULL, 0, 0))
  53.           {
  54.           TranslateMessage (&msg) ;
  55.           DispatchMessage (&msg) ;
  56.           }
  57.      return msg.wParam ;
  58.      }
  59.  
  60. LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  61.      {
  62.      static BOOL   fDoingInitiate = TRUE ;
  63.      static char   szServerApp[]  = "DdePop1",
  64.                    szTopic[]      = "US_Population" ;
  65.      static HWND   hwndServer = NULL ;
  66.      static long   cxChar, cyChar ;
  67.      ATOM          aApp, aTop, aItem ;
  68.      char          szBuffer[24], szPopulation[16], szItem[16] ;
  69.      DDEACK        DdeAck ;
  70.      DDEDATA      *pDdeData ;
  71.      DDEADVISE    *pDdeAdvise ;
  72.      DWORD         dwTime ;
  73.      GLOBALHANDLE  hDdeAdvise, hDdeData ;
  74.      HDC           hdc ;
  75.      MSG           msg ;
  76.      PAINTSTRUCT   ps ;
  77.      short         i ;
  78.      long          x, y ;
  79.      TEXTMETRIC    tm ;
  80.      WORD          wStatus ;
  81.      UINT          uiLow, uiHi ;
  82.  
  83.      switch (iMsg)
  84.           {
  85.           case WM_CREATE :
  86.                hdc = GetDC (hwnd) ;
  87.                GetTextMetrics (hdc, &tm) ;
  88.                cxChar = tm.tmAveCharWidth ;
  89.                cyChar = tm.tmHeight + tm.tmExternalLeading ;
  90.                ReleaseDC (hwnd, hdc) ;
  91.                return 0 ;
  92.  
  93.           case WM_USER_INITIATE :
  94.  
  95.                      // Broadcast WM_DDE_INITIATE iMsg
  96.  
  97.                aApp = GlobalAddAtom (szServerApp) ;
  98.                aTop = GlobalAddAtom (szTopic) ;
  99.  
  100.                SendMessage (HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM) hwnd,
  101.                             MAKELONG (aApp, aTop)) ;
  102.  
  103.                      // If no response, try loading DDEPOP first
  104.  
  105.                if (hwndServer == NULL)
  106.                     {
  107.                     WinExec (szServerApp, SW_SHOWMINNOACTIVE) ;
  108.  
  109.                     SendMessage (HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM) hwnd,
  110.                                  MAKELONG (aApp, aTop)) ;
  111.                     }
  112.  
  113.                     // Delete the atoms
  114.  
  115.                GlobalDeleteAtom (aApp) ;
  116.                GlobalDeleteAtom (aTop) ;
  117.                fDoingInitiate = FALSE ;
  118.  
  119.                     // If still no response, display message box
  120.  
  121.                if (hwndServer == NULL)
  122.                     {
  123.                     MessageBox (hwnd, "Cannot connect with DDEPOP1.EXE!",
  124.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  125.  
  126.                     return 0 ;
  127.                     }
  128.  
  129.                     // Post WM_DDE_ADVISE iMsgs
  130.  
  131.                for (i = 0 ; i < NUM_STATES ; i++)
  132.                     {
  133.                     hDdeAdvise = GlobalAlloc (GHND | GMEM_DDESHARE,
  134.                                               sizeof (DDEADVISE)) ;
  135.  
  136.                     pDdeAdvise = (DDEADVISE *) GlobalLock (hDdeAdvise) ;
  137.  
  138.                     pDdeAdvise->fAckReq   = TRUE ;
  139.                     pDdeAdvise->fDeferUpd = FALSE ;
  140.                     pDdeAdvise->cfFormat  = CF_TEXT ;
  141.  
  142.                     GlobalUnlock (hDdeAdvise) ;
  143.  
  144.                     aItem = GlobalAddAtom (pop[i].szAbb) ;
  145.  
  146.                     if (!PostMessage (hwndServer, WM_DDE_ADVISE, (WPARAM) hwnd,
  147.                                       PackDDElParam (WM_DDE_ADVISE,
  148.                                                      (UINT) hDdeAdvise, aItem)))
  149.                          {
  150.                          GlobalFree (hDdeAdvise) ;
  151.                          GlobalDeleteAtom (aItem) ;
  152.                          break ;
  153.                          }
  154.  
  155.                     DdeAck.fAck = FALSE ;
  156.  
  157.                     dwTime = GetCurrentTime () ;
  158.  
  159.                     while (GetCurrentTime () - dwTime < DDE_TIMEOUT)
  160.                          {
  161.                          if (PeekMessage (&msg, hwnd, WM_DDE_ACK,
  162.                                           WM_DDE_ACK, PM_REMOVE))
  163.                               {
  164.                               GlobalDeleteAtom (HIWORD (msg.lParam)) ;
  165.  
  166.                               wStatus = LOWORD (msg.lParam) ;
  167.                               DdeAck = *((DDEACK *) &wStatus) ;
  168.  
  169.                               if (DdeAck.fAck == FALSE)
  170.                                    GlobalFree (hDdeAdvise) ;
  171.  
  172.                               break ;
  173.                               }
  174.                          }
  175.  
  176.                     if (DdeAck.fAck == FALSE)
  177.                          break ;
  178.  
  179.                     while (PeekMessage (&msg, hwnd, WM_DDE_FIRST,
  180.                                         WM_DDE_LAST, PM_REMOVE))
  181.                          {
  182.                          DispatchMessage (&msg) ;
  183.                          }
  184.                     }
  185.  
  186.                if (i < NUM_STATES)
  187.                     {
  188.                     MessageBox (hwnd, "Failure on WM_DDE_ADVISE!",
  189.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  190.                     }
  191.                return 0 ;
  192.  
  193.           case WM_DDE_ACK :
  194.  
  195.                     // In response to WM_DDE_INITIATE, save server window
  196.  
  197.                if (fDoingInitiate)
  198.                     {
  199.                     UnpackDDElParam (WM_DDE_ACK, lParam, &uiLow, &uiHi) ;
  200.                     FreeDDElParam (WM_DDE_ACK, lParam) ;
  201.                     hwndServer = (HWND) wParam ;
  202.                     GlobalDeleteAtom ((ATOM) uiLow) ;
  203.                     GlobalDeleteAtom ((ATOM) uiHi) ;
  204.                     }
  205.                return 0 ;
  206.  
  207.           case WM_DDE_DATA :
  208.  
  209.                     // wParam -- sending window handle
  210.                     // lParam -- DDEDATA memory handle & item atom
  211.  
  212.                UnpackDDElParam (WM_DDE_DATA, lParam, &uiLow, &uiHi) ;
  213.                FreeDDElParam (WM_DDE_DATA, lParam) ;
  214.  
  215.                hDdeData  = (GLOBALHANDLE) uiLow ;
  216.                pDdeData = (DDEDATA *) GlobalLock (hDdeData) ;
  217.                aItem     = (ATOM) uiHi ;
  218.  
  219.                     // Initialize DdeAck structure
  220.  
  221.                DdeAck.bAppReturnCode = 0 ;
  222.                DdeAck.reserved       = 0 ;
  223.                DdeAck.fBusy          = FALSE ;
  224.                DdeAck.fAck           = FALSE ;
  225.  
  226.                     // Check for matching format and data item
  227.  
  228.                if (pDdeData->cfFormat == CF_TEXT)
  229.                     {
  230.                     GlobalGetAtomName (aItem, szItem, sizeof (szItem)) ;
  231.  
  232.                     for (i = 0 ; i < NUM_STATES ; i++)
  233.                          if (strcmp (szItem, pop[i].szAbb) == 0)
  234.                               break ;
  235.  
  236.                     if (i < NUM_STATES)
  237.                          {
  238.                          strcpy (szPopulation, (char *) pDdeData->Value) ;
  239.                          pop[i].lPop = atol (szPopulation) ;
  240.                          InvalidateRect (hwnd, NULL, FALSE) ;
  241.  
  242.                          DdeAck.fAck = TRUE ;
  243.                          }
  244.                     }
  245.  
  246.                     // Acknowledge if necessary
  247.  
  248.                if (pDdeData->fAckReq == TRUE)
  249.                     {
  250.                     wStatus = *((WORD *) &DdeAck) ;
  251.  
  252.                     if (!PostMessage ((HWND) wParam, WM_DDE_ACK, (WPARAM) hwnd,
  253.                                       PackDDElParam (WM_DDE_ACK,
  254.                                                      wStatus, aItem)))
  255.                          {
  256.                          GlobalDeleteAtom (aItem) ;
  257.                          GlobalUnlock (hDdeData) ;
  258.                          GlobalFree (hDdeData) ;
  259.                          return 0 ;
  260.                          }
  261.                     }
  262.                else
  263.                     {
  264.                     GlobalDeleteAtom (aItem) ;
  265.                     }
  266.  
  267.                     // Clean up
  268.  
  269.                if (pDdeData->fRelease == TRUE || DdeAck.fAck == FALSE)
  270.                     {
  271.                     GlobalUnlock (hDdeData) ;
  272.                     GlobalFree (hDdeData) ;
  273.                     }
  274.                else
  275.                     {
  276.                     GlobalUnlock (hDdeData) ;
  277.                     }
  278.  
  279.                return 0 ;
  280.  
  281.           case WM_PAINT :
  282.                hdc = BeginPaint (hwnd, &ps) ;
  283.  
  284.                for (i = 0 ; i < NUM_STATES ; i++)
  285.                     {
  286.                     if (i < (NUM_STATES + 1) / 2)
  287.                          {
  288.                          x = cxChar ;
  289.                          y = i * cyChar ;
  290.                          }
  291.                     else
  292.                          {
  293.                          x = 44 * cxChar ;
  294.                          y = (i - (NUM_STATES + 1) / 2) * cyChar ;
  295.                          }
  296.  
  297.                     TextOut (hdc, x, y, szBuffer,
  298.                              wsprintf (szBuffer, "%-20s",
  299.                                        (PSTR) pop[i].szState)) ;
  300.  
  301.                     x += 36 * cxChar ;
  302.  
  303.                     SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
  304.  
  305.                     TextOut (hdc, x, y, szBuffer,
  306.                              wsprintf (szBuffer, "%10ld", pop[i].lPop)) ;
  307.  
  308.                     SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
  309.                     }
  310.  
  311.                EndPaint (hwnd, &ps) ;
  312.                return 0 ;
  313.  
  314.           case WM_DDE_TERMINATE :
  315.  
  316.                     // Respond with another WM_DDE_TERMINATE iMsg
  317.  
  318.                PostMessage (hwndServer, WM_DDE_TERMINATE, (WPARAM) hwnd, 0L) ;
  319.                hwndServer = NULL ;
  320.                return 0 ;
  321.  
  322.           case WM_CLOSE :
  323.                if (hwndServer == NULL)
  324.                     break ;
  325.  
  326.                     // Post WM_DDE_UNADVISE iMsg
  327.  
  328.                PostMessage (hwndServer, WM_DDE_UNADVISE, (WPARAM) hwnd,
  329.                             MAKELONG (CF_TEXT, NULL)) ;
  330.  
  331.                dwTime = GetCurrentTime () ;
  332.  
  333.                while (GetCurrentTime () - dwTime < DDE_TIMEOUT)
  334.                     {
  335.                     if (PeekMessage (&msg, hwnd, WM_DDE_ACK,
  336.                                      WM_DDE_ACK, PM_REMOVE))
  337.                          break ;
  338.                     }
  339.  
  340.                     // Post WM_DDE_TERMINATE iMsg
  341.  
  342.                PostMessage (hwndServer, WM_DDE_TERMINATE, (WPARAM) hwnd, 0L) ;
  343.  
  344.                dwTime = GetCurrentTime () ;
  345.  
  346.                while (GetCurrentTime () - dwTime < DDE_TIMEOUT)
  347.                     {
  348.                     if (PeekMessage (&msg, hwnd, WM_DDE_TERMINATE,
  349.                                      WM_DDE_TERMINATE, PM_REMOVE))
  350.                          break ;
  351.                     }
  352.  
  353.                break ;             // for default processing
  354.  
  355.           case WM_DESTROY :
  356.                PostQuitMessage (0) ;
  357.                return 0 ;
  358.           }
  359.      return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
  360.      }
  361.